package compiler;

import javax.tools.DiagnosticCollector;
import javax.tools.JavaCompiler;
import javax.tools.JavaFileObject;
import javax.tools.StandardJavaFileManager;
import javax.tools.ToolProvider;
import java.io.File;
import java.lang.reflect.Method;
import java.security.AccessController;
import java.security.PrivilegedAction;
import java.util.Arrays;
import java.util.Collections;


public class DynamicCompiler {

    // 简单的Java源代码，我们打算编译并运行它
    static final String sourceCode = "public class HelloWorld {"
            + "    public static void main(String[] args) {"
            + "        System.out.println(\"Hello, World! (from compiled code)\");"
            + "    }"
            + "}";

    static final String outputDir = System.getProperty("user.dir")
            + File.separator + "target"
            + File.separator + "classes"
            + File.separator + "dynamicCompiler";
    static {
        File file = new File(outputDir);
        if(!file.exists()){
            file.mkdirs();
        }
    }

    public static void main(String[] args) throws Exception {
        // 获取系统Java编译器
        JavaCompiler compiler = ToolProvider.getSystemJavaCompiler();
        //初始化诊断收集器
        DiagnosticCollector<JavaFileObject> diagnostics = new DiagnosticCollector<>();

        // 使用标准文件管理器
        try (StandardJavaFileManager fileManager = compiler.getStandardFileManager(diagnostics, null, null)) {

            // 创建一个Java源代码文件对象（内存中的）
            JavaFileObject file = new JavaSourceFromString("HelloWorld", sourceCode);

            // 获取编译任务
            Iterable<? extends JavaFileObject> compilationUnits = Collections.singletonList(file);
            JavaCompiler.CompilationTask task = compiler.getTask(null, fileManager, diagnostics,
                    Arrays.asList("-d", outputDir) , null, compilationUnits);

            // 执行编译
            boolean success = task.call();

            // 输出编译诊断信息
            if (!success) {
                diagnostics.getDiagnostics().forEach(diag -> {
                    System.out.format("Error on line %d in %s%n",
                            diag.getLineNumber(),
                            diag.getSource().toUri());
                });
            } else {
                // 编译成功，现在加载并执行类
                final ClassLoader loader = Thread.currentThread().getContextClassLoader();
                ClassLoader classLoader = AccessController.doPrivileged(
                        (PrivilegedAction<ClassLoaderImpl>) () -> new ClassLoaderImpl(loader,outputDir));
                Class<?> cls = classLoader.loadClass("HelloWorld");
                Method mainMethod = cls.getMethod("main", String[].class);
                mainMethod.invoke(null, (Object) new String[]{});
            }
        }
    }
}